using System;
using System.Collections.Generic;
using System.Linq;
using WatiN.Core;
using WatiN.Core.Constraints;
using YatFram.Browser.CssSelector;

namespace YatFram.Browser.Watin
{
    public static class WatinConstraints
    {
        private static readonly IDictionary<Func<CssSelectors, Selector>, Func<string, Constraint>> watinConstraints = new Dictionary<Func<CssSelectors, Selector>, Func<string, Constraint>>
                                                                                                                            {
                                                                                                                                {cs => cs.Id, Find.ById},
                                                                                                                                {cs => cs.Class, Find.ByClass},
                                                                                                                                {cs => cs.Name, Find.ByName},
                                                                                                                            };
        
        public static Constraint ToConstraint(this CssSelectors selector)
        {
            var constraints = watinConstraints.Where(a => a.Key(selector) != Selector.NoSelector).Select(a => a.Value(a.Key(selector).ToString()));
            return constraints.Aggregate((seed, currentConstraint) => seed.And(currentConstraint));
        }

        public static Element FindElement(this IE driver, string cssSelector)
        {
            var constraints = GetConstraints(cssSelector);
            var firstConstraint = constraints.First();
            var restOfTheConstrains = constraints.Skip(1);
            return restOfTheConstrains.Aggregate(driver.Element(firstConstraint), NextElement);
        }

        public static Element FindElement(this Element element, string cssSelector)
        {
            var constraints = GetConstraints(cssSelector);
            var firstConstraint = constraints.First();
            var restOfTheConstrains = constraints.Skip(1);
            return restOfTheConstrains.Aggregate(element.DomContainer.Element(firstConstraint), NextElement);
        }

        private static Element NextElement(Element element, Constraint constraint)
        {
            return element.DomContainer.Element(constraint);
        }

        private static IEnumerable<Constraint> GetConstraints(string cssSelector)
        {
            var cssSelectorsList = cssSelector.ToCssSelectors();
            return cssSelectorsList.Select(selector => ToConstraint(selector));
        }

    }
}